package com.cicadasmall.weixin;
import com.cicadasmall.weixin.properties.RedisProperties;
import com.cicadasmall.weixin.properties.WxMpProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.*;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;


/**
 * WxMpConfig
 *
 * @author Jin
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(WxMpProperties.class)
public class WxMpConfig {

    /**
     * 微信公众号相关服务自动注册.
     *
     * @author someone
     */
    @Configuration
    public class WxMpServiceAutoConfiguration {

        @Bean
        @ConditionalOnMissingBean
        public WxMpService wxMpService(WxMpConfigStorage configStorage) {
            WxMpService wxMpService = new WxMpServiceImpl();
            wxMpService.setWxMpConfigStorage(configStorage);
            return wxMpService;
        }

        @Bean
        public WxMpKefuService wxMpKefuService(WxMpService wxMpService) {
            return wxMpService.getKefuService();
        }

        @Bean
        public WxMpMaterialService wxMpMaterialService(WxMpService wxMpService) {
            return wxMpService.getMaterialService();
        }

        @Bean
        public WxMpMenuService wxMpMenuService(WxMpService wxMpService) {
            return wxMpService.getMenuService();
        }

        @Bean
        public WxMpUserService wxMpUserService(WxMpService wxMpService) {
            return wxMpService.getUserService();
        }

        @Bean
        public WxMpUserTagService wxMpUserTagService(WxMpService wxMpService) {
            return wxMpService.getUserTagService();
        }

        @Bean
        public WxMpQrcodeService wxMpQrcodeService(WxMpService wxMpService) {
            return wxMpService.getQrcodeService();
        }

        @Bean
        public WxMpCardService wxMpCardService(WxMpService wxMpService) {
            return wxMpService.getCardService();
        }

        @Bean
        public WxMpDataCubeService wxMpDataCubeService(WxMpService wxMpService) {
            return wxMpService.getDataCubeService();
        }

        @Bean
        public WxMpUserBlacklistService wxMpUserBlacklistService(WxMpService wxMpService) {
            return wxMpService.getBlackListService();
        }

        @Bean
        public WxMpStoreService wxMpStoreService(WxMpService wxMpService) {
            return wxMpService.getStoreService();
        }

        @Bean
        public WxMpTemplateMsgService wxMpTemplateMsgService(WxMpService wxMpService) {
            return wxMpService.getTemplateMsgService();
        }

        @Bean
        public WxMpSubscribeMsgService wxMpSubscribeMsgService(WxMpService wxMpService) {
            return wxMpService.getSubscribeMsgService();
        }

        @Bean
        public WxMpDeviceService wxMpDeviceService(WxMpService wxMpService) {
            return wxMpService.getDeviceService();
        }

        @Bean
        public WxMpShakeService wxMpShakeService(WxMpService wxMpService) {
            return wxMpService.getShakeService();
        }

        @Bean
        public WxMpMemberCardService wxMpMemberCardService(WxMpService wxMpService) {
            return wxMpService.getMemberCardService();
        }

        @Bean
        public WxMpMassMessageService wxMpMassMessageService(WxMpService wxMpService) {
            return wxMpService.getMassMessageService();
        }

        @Bean
        public WxMpAiOpenService wxMpAiOpenService(WxMpService wxMpService) {
            return wxMpService.getAiOpenService();
        }

        @Bean
        public WxMpWifiService wxMpWifiService(WxMpService wxMpService) {
            return wxMpService.getWifiService();
        }

        @Bean
        public WxMpMarketingService wxMpMarketingService(WxMpService wxMpService) {
            return wxMpService.getMarketingService();
        }

        @Bean
        public WxMpCommentService wxMpCommentService(WxMpService wxMpService) {
            return wxMpService.getCommentService();
        }

        @Bean
        public WxMpOcrService wxMpOcrService(WxMpService wxMpService) {
            return wxMpService.getOcrService();
        }

    }




    /**
     * 微信公众号存储策略自动配置.
     *
     * @author someone
     */
    @Configuration
    @RequiredArgsConstructor
    public class WxMpStorageAutoConfiguration {
        private final WxMpProperties properties;

        @Autowired(required = false)
        private JedisPool jedisPool;

        @Autowired(required = false)
        private RedissonClient redissonClient;

        @Bean
        @ConditionalOnMissingBean(WxMpConfigStorage.class)
        public WxMpConfigStorage wxMpInMemoryConfigStorage() {
            WxMpProperties.ConfigStorage storage = properties.getConfigStorage();
            WxMpProperties.StorageType type = storage.getType();

            if (type == WxMpProperties.StorageType.redis) {
                return getWxMpInRedisConfigStorage();
            }
            return getWxMpInMemoryConfigStorage();
        }

        private WxMpDefaultConfigImpl getWxMpInMemoryConfigStorage() {
            WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl();
            setWxMpInfo(config);
            return config;
        }

        private WxMpRedisConfigImpl getWxMpInRedisConfigStorage() {
            JedisPool poolToUse = jedisPool;
            if (poolToUse == null) {
                poolToUse = getJedisPool();
            }
            WxMpRedisConfigImpl config = new WxMpRedisConfigImpl(poolToUse);
            setWxMpInfo(config);
            return config;
        }

        private void setWxMpInfo(WxMpDefaultConfigImpl config) {
            config.setAppId(properties.getAppId());
            config.setSecret(properties.getSecret());
            config.setToken(properties.getToken());
            config.setAesKey(properties.getAesKey());
        }

        private JedisPool getJedisPool() {
            WxMpProperties.ConfigStorage storage = properties.getConfigStorage();
            RedisProperties redis = storage.getRedis();

            JedisPoolConfig config = new JedisPoolConfig();
            if (redis.getMaxActive() != null) {
                config.setMaxTotal(redis.getMaxActive());
            }
            if (redis.getMaxIdle() != null) {
                config.setMaxIdle(redis.getMaxIdle());
            }
            if (redis.getMaxWaitMillis() != null) {
                config.setMaxWaitMillis(redis.getMaxWaitMillis());
            }
            if (redis.getMinIdle() != null) {
                config.setMinIdle(redis.getMinIdle());
            }
            config.setTestOnBorrow(true);
            config.setTestWhileIdle(true);

            JedisPool pool = new JedisPool(config, redis.getHost(), redis.getPort(),
                    redis.getTimeout(), redis.getPassword(), redis.getDatabase());
            return pool;
        }
    }


}
